#ifndef __VMM_H__
#define __VMM_H__

#include <types.h>
#include <list.h>

#include <multiboot.h>
#include <sys/unistd.h>
#include <sys/task.h>

/* max user virtual addr 8 */
#define USER_MAX_ADDR	        0xE0000000
#define USER_STACK	        0xD0000000

#define VM_NEW_MEM              0x00    /* new child mem image */
#define VM_SHARE_MEM            0x01    /* child share mem image with parent */
#define VM_COPY_MEM             0x02    /* copying parent's mem to child */

#define MEMREG_READ		0x00000001
#define MEMREG_WRITE	        0x00000002
#define MEMREG_SHARED	        0x00000004
#define MEMREG_EXEC		0x00000008
#define MEMREG_MAPPED	        0x00000010
#define MEMREG_FREE		0x00000080

#define ATTR_NONE       0x00
#define ATTR_RD         0x01
#define ATTR_WR         0x02
#define ATTR_EXEC       0x04

typedef struct memreg memreg_t;

/* mem region as page */
struct memreg {
    struct memreg *next;
    struct memreg *prev;
    struct memreg *sh_prev;
    struct memreg *sh_next;
    
    uint32_t flags;		/* policy */
    addr_t vbase;		/* virtual base addr */
    addr_t addr;		/* physical addr of mem region */
    size_t reg_size;		/* size of mem region */
};

typedef struct vm_map vm_map_t;

/* virtual memory map , one per task */
struct vm_map {
    addr_t pdir;	/* page directory addr */
    size_t map_size;	/* the size of vm region */
    memreg_t reglst;	/* list of mem regions */
    int refcount;
};

void vm_init(void);
vm_map_t *vm_create(void);
int vm_alloc(task_t *, void **, size_t, int);
void vm_terminate(vm_map_t *);
int vm_free(task_t *, void *);
int vm_attribute(task_t *, void *, int);
int vm_map(task_t *, void *, size_t, void **);
vm_map_t *vm_dup(vm_map_t *);
int vm_load(vm_map_t *, module_t *, void **);
addr_t vm_trans(addr_t, size_t);
void vm_ref(vm_map_t *);

void memreg_init(memreg_t *);
memreg_t *memreg_create(memreg_t *, addr_t, size_t);
memreg_t *memreg_alloc(memreg_t *, size_t);
void memreg_destroy(memreg_t *, memreg_t *);
memreg_t *memreg_lock(memreg_t *, addr_t, size_t);
void memreg_free(memreg_t *, memreg_t *);
memreg_t *memreg_lookup(memreg_t *, addr_t, size_t);

int copyin(const void *uaddr, void *kaddr, size_t len);
int copyout(const void *kaddr, void *uaddr, size_t len);
int copyinstr(const void *uaddr, void *kaddr, size_t len);

#endif  /* __VMM_H__ */
